#pragma once

#include <string>
#include <map>

#include "..\..\Interfaces\IShader.h"
#include "..\..\Interfaces\IShaderSystem.h"
#include "..\..\Interfaces\IAnnotationHandler.h"
#include "..\..\Interfaces\ISemanticHandler.h"
#include "..\..\Interfaces\ICallbackHandler.h"

struct AnnotationHandlerContainer
{
	AnnotationHandlerContainer()
		: Handler(NULL)
		, Handle(NULL)
		, FromSystem(false)
	{}

	~AnnotationHandlerContainer()
	{
		if (!FromSystem && Handler)
			delete Handler;
	}

	IAnnotationHandler* Handler;
	D3DXHANDLE Handle;
	bool FromSystem;
};


struct CallbackHandlerContainer
{
	CallbackHandlerContainer()
		: Handler(NULL)
		, FromSystem(false)
	{}

	~CallbackHandlerContainer()
	{
		if (!FromSystem && Handler)
			delete Handler;
	}

	ICallbackHandler* Handler;
	std::map<unsigned int, D3DXHANDLE> PassList;
	bool FromSystem;	
};

struct SemanticHandlerContainer
{
	SemanticHandlerContainer()
		: Handler(NULL)
		, Parameter(NULL)
		, FromSystem(false)
	{}

	~SemanticHandlerContainer()
	{
		if (!FromSystem && Handler)
			delete Handler;
	}

	ISemanticHandler* Handler;
	IShaderParameter* Parameter;
	bool FromSystem;
};


class Shader :
	public IShader
{
public:
	Shader(IDirect3DDevice9* inDevice, IShaderSystem* inSystem, const std::string& inShaderName, const std::string& inShaderCode, const std::string& inShaderFileName);
	virtual ~Shader();

	virtual RenderPassReturnValue::Enumeration BeginPass(unsigned int inPassNumber);
	virtual void EndPass();

	virtual unsigned int get_PassCount();
	virtual unsigned int Begin();
	virtual unsigned int Begin(const std::string& techniqueName);

	virtual void End();

	virtual const std::string& get_Name() const;

	virtual bool AddAnnotationHandler(IAnnotationHandler* inAnnotationHandler);
	virtual bool RemoveAnnotationHandler(IAnnotationHandler* inAnnotationHandler);
	virtual bool RemoveAnnotationHandler(const std::string& inAnnotationHandlerName);
	virtual IAnnotationHandler* get_AnnotationHandler(const std::string& inAnnotationHandlerName) const;

	virtual bool AddCallbackHandler(ICallbackHandler* inCallbackHandler);
	virtual bool RemoveCallbackHandler(ICallbackHandler* inCallbackHandler);
	virtual bool RemoveCallbackHandler(const std::string& inCallbackHandlerName);
	virtual ICallbackHandler* get_CallbackHandler(const std::string& inCallbackHandlerName) const;

	virtual bool AddSemanticHandler(ISemanticHandler* inSemanticHandler);
	virtual bool RemoveSemanticHandler(ISemanticHandler* inSemanticHandler);
	virtual bool RemoveSemanticHandler(const std::string& inSemanticHandlerName);
	virtual ISemanticHandler* get_SemanticHandler(const std::string& inSemanticHandlerName) const;

	virtual IShaderParameter* get_ParameterByName(const std::string& inName, ShaderParameterType::Enumeration inType=ShaderParameterType::Unknown);
	virtual IShaderParameter* get_ParameterBySemantic(const std::string& inName, ShaderParameterType::Enumeration inType=ShaderParameterType::Unknown);
	virtual const std::vector<IShaderParameter*>& get_ParameterList() const;

	virtual bool isValid() const;
	virtual const std::string& get_ShaderErrors() const;

	virtual void Refresh(IDirect3DDevice9* inDevice);

	virtual ID3DXEffect* get_Effect();

public:
	virtual bool AddSystemAnnotationHandler(IAnnotationHandler* inAnnotationHandler);
	virtual bool AddSystemCallbackHandler(ICallbackHandler* inCallbackHandler);
	virtual bool AddSystemSemanticHandler(ISemanticHandler* inSemanticHandler);

private:
	void InitShader();
	void LoadShader();
	void CreateShader();
	void SelectBestTechnique();
	void ActivateSemanticHandlers();
	void ActivateAnnotationHandlers();
	RenderPassReturnValue::Enumeration ActivateCallbackHandlers(unsigned int Pass);
	void FillCallbackhandlerContainer(CallbackHandlerContainer* inContainer);

	std::map<std::string, AnnotationHandlerContainer> AnnotationHandlerList;
	std::map<std::string, SemanticHandlerContainer> SemanticHandlerList;
	std::map<std::string, CallbackHandlerContainer> CallbackHandlerList;
	std::vector<IShaderParameter*> ParameterList;

	IDirect3DDevice9* Device;
	IShaderSystem* System;

	std::string Name;
	std::string Code;
	std::string Filename;

	bool Valid;
	std::string Errors;

	bool PassStarted;

	ID3DXEffect* Effect;
	D3DXHANDLE Technique;
};
